#!/usr/bin/env python
# -*- coding: utf-8 -*-

try:
    import json
except ImportError:
    import simplejson as json
import time
import urllib
import urllib2
import logging
from Queue import Queue
from threading import Thread
import threading
def _obj_hook(pairs):
    '''
    convert json object to python object.
    '''
    o = JsonObject()
    for k, v in pairs.iteritems():
        o[str(k)] = v
    return o

class APIError(StandardError):
    '''
    raise APIError if got failed json message.
    '''
    def __init__(self, error_code, error, request):
        self.error_code = error_code
        self.error = error
        self.request = request
        StandardError.__init__(self, error)

    def __str__(self):
        return 'APIError: %s: %s, request: %s' % (self.error_code, self.error, self.request)

class JsonObject(dict):
    '''
    general json object that can bind any fields but also act as a dict.
    '''
    def __getattr__(self, attr):
        return self[attr]

    def __setattr__(self, attr, value):
        self[attr] = value

def _encode_params(**kw):
    '''
    Encode parameters.
    '''
    args = []
    for k, v in kw.iteritems():
        qv = v.encode('utf-8') if isinstance(v, unicode) else str(v)
        args.append('%s=%s' % (k, urllib.quote(qv)))
    return '&'.join(args)

def _encode_multipart(**kw):
    '''
    Build a multipart/form-data body with generated random boundary.
    '''
    boundary = '----------%s' % hex(int(time.time() * 1000))
    data = []
    for k, v in kw.iteritems():
        data.append('--%s' % boundary)
        if hasattr(v, 'read'):
            # file-like object:
            ext = ''
            filename = getattr(v, 'name', '')
            n = filename.rfind('.')
            if n != (-1):
                ext = filename[n:].lower()
            content = v.read()
            data.append('Content-Disposition: form-data  name="%s"  filename="hidden"' % k)
            data.append('Content-Length: %d' % len(content))
            data.append('Content-Type: %s\r\n' % _guess_content_type(ext))
            data.append(content)
        else:
            data.append('Content-Disposition: form-data  name="%s"\r\n' % k)
            data.append(v.encode('utf-8') if isinstance(v, unicode) else v)
    data.append('--%s--\r\n' % boundary)
    return '\r\n'.join(data), boundary

_CONTENT_TYPES = { '.png': 'image/png', '.gif': 'image/gif', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.jpe': 'image/jpeg' }

def _guess_content_type(ext):
    return _CONTENT_TYPES.get(ext, 'application/octet-stream')

_HTTP_GET = 0
_HTTP_POST = 1
_HTTP_UPLOAD = 2

def _http_get(url, authorization=None, **kw):
    logging.info('GET %s' % url)
    return _http_call(url, _HTTP_GET, authorization, **kw)

def _http_post(url, authorization=None, **kw):
    logging.info('POST %s' % url)
    return _http_call(url, _HTTP_POST, authorization, **kw)

def _http_upload(url, authorization=None, **kw):
    logging.info('MULTIPART POST %s' % url)
    return _http_call(url, _HTTP_UPLOAD, authorization, **kw)

def _http_call(url, method, authorization, **kw):
    '''
    send an http request and expect to return a json object if no error.
    '''
    params = None
    boundary = None
    if method==_HTTP_UPLOAD:
        params, boundary = _encode_multipart(**kw)
    else:
        params = _encode_params(**kw)
    http_url = '%s?%s' % (url, params) if method==_HTTP_GET else url
    http_body = None if method==_HTTP_GET else params
    req = urllib2.Request(http_url, data=http_body)
    if authorization:
        req.add_header('Authorization', 'OAuth2 %s' % authorization)
    if boundary:
        req.add_header('Content-Type', 'multipart/form-data  boundary=%s' % boundary)
    resp = ''
    fails = 0
    while True:
        try:
            if fails > 2:
                break
            resp = urllib2.urlopen(req, timeout=9)
        except urllib2.URLError, e: 
            fails += 1
            logging.error('Error:%s when url:%s fails:%s' % (e, http_url, fails))
            time.sleep(9)
        else:
            break
    body = resp.read()
    r = json.loads(body, object_hook=_obj_hook)
    if hasattr(r, 'error_code'):
        raise APIError(r.error_code, getattr(r, 'error', ''), getattr(r, 'request', ''))
    return r

class HttpObject(object):

    def __init__(self, client, method):
        self.client = client
        self.method = method

    def __getattr__(self, attr):
        def wrap(**kw):
            if self.client.is_expires():
                raise APIError('21327', 'expired_token', attr)
            return _http_call('%s%s.json' % (self.client.api_url, attr.replace('__', '/')), self.method, self.client.access_token, **kw)
        return wrap

class APIClient(object):
    '''
    API client using synchronized invocation.
    '''
    def __init__(self, app_key, app_secret, redirect_uri=None, response_type='code', domain='api.weibo.com', version='2'):
        self.client_id = app_key
        self.client_secret = app_secret
        self.redirect_uri = redirect_uri
        self.response_type = response_type
        self.auth_url = 'https://%s/oauth2/' % domain
        self.api_url = 'https://%s/%s/' % (domain, version)
        self.access_token = None
        self.expires = 0.0
        self.get = HttpObject(self, _HTTP_GET)
        self.post = HttpObject(self, _HTTP_POST)
        self.upload = HttpObject(self, _HTTP_UPLOAD)

    def set_access_token(self, access_token, expires_in):
        self.access_token = str(access_token)
        self.expires = float(expires_in)

    def get_authorize_url(self, redirect_uri=None, display='default'):
        '''
        return the authroize url that should be redirect.
        '''
        redirect = redirect_uri if redirect_uri else self.redirect_uri
        if not redirect:
            raise APIError('21305', 'Parameter absent: redirect_uri', 'OAuth2 request')
        return '%s%s?%s' % (self.auth_url, 'authorize', \
                _encode_params(client_id = self.client_id, \
                        response_type = 'code', \
                        display = display, \
                        redirect_uri = redirect))

    def request_access_token(self, code, redirect_uri=None, uname='', upassword=''):
        '''
        return access token as object: {"access_token":"your-access-token","expires_in":12345678}, expires_in is standard unix-epoch-time
        '''
        redirect = redirect_uri if redirect_uri else self.redirect_uri
        g_type = 'authorization_code'
        if not redirect:
            g_type = 'password'
        r = _http_post('%s%s' % (self.auth_url, 'access_token'), \
                client_id = self.client_id, \
                client_secret = self.client_secret, \
                username = uname, password = upassword, \
                code = code, grant_type = g_type)
        r.expires_in += int(time.time())
        return r

    def is_expires(self):
        return not self.access_token or time.time() > self.expires

    def __getattr__(self, attr):
        return getattr(self.get, attr)
def get_statuses_ids_by_uid(client,user_id):
    m= 0
    midlist = []
    user_name = client.get.users__show(uid = user_id).screen_name
    for i in range(0,9):
        statuses = client.get.statuses__user_timeline(screen_name = user_name,count = 100).statuses
        for x in statuses:
            if m > 19:
                return midlist
            if x.reposts_count > 2000:
                midlist.append(str(x.idstr))
                m = m + 1
            else:
                pass
    return midlist
    
def get_statuses_ids_by_query(client,search_query,stat_time,end_time):
    m = 0
    midlist = []
    for i in range(1,20):
        results = client.get.search__statuses(q = search_query, count = 50,page = i,filter_ori = 5,starttime = start_time, endtime = end_time)
        statuses = results.statuses
        for x in statuses:
            print x.reposts_count
            if m > 9:
                return midlist
            if x.reposts_count > 2000:
                midlist.append(str(x.id))
                m = m + 1
            else:
                pass
        return midlist
def get_repost_uid(client,mid):
    uid_list = []
    for i in range(1,10):
        time.sleep(0.1)
        try:
            reposts = client.get.statuses__repost_timeline(id = mid,count = 200,page = i).reposts
            for x in reposts:
                uid_list.append(x.user.idstr)
        except:
            pass
    return uid_list   
def get_navy_followers(client,initial):
    followers = set()
    for x in initial:
        try:
            time.sleep(0.1)
            total_num = client.get.friendships__followers(uid = x,count = 200).total_number
            i = 0
            print total_num
            while i <total_num:
                try:
                    users = client.get.friendships__followers(uid = x,count = 200,cursor = i).users
                    i = i + 200
                    for m in users:
                        followers.add(m.idstr)
                except:
                    break
            pass
        except:
            pass
    return followers
def identify_navy(client,Uid,initial):
    friends = set()
    total_num = client.get.friendships__friends(uid = Uid,count = 3).total_number
    i = 0
    while(i <total_num - 200):
        try:
            users = client.get.friendships__friends(uid = Uid,count = 200,cursor = i).users
            i = i + 200
            for x in users:
                friends.add(x.idstr)
        except:
            break
    occur = friends & initial
    if len(occur) > 1:
        return 0
    else:
        return 1       
def run(mids,client):
    global info
    global all_id_table
    global Navy_initial
    global Normal_initial
    while True:
        time.sleep(0.1)
        if mids.empty():
            print "队列中已无对象"
            return info
        mid = mids.get()
        try:
            info[mid] = get_repost_uid(client,mid)
            for x in info[mid]:
                all_id_table[x] = all_id_table.get(x,0) + info[mid].count(x)
                if info[mid].count(x) > 5:
                    Navy_initial.add(x)
                if info[mid].count(x) == 1:
                    Normal_initial.add(x)
            print mid
        except:
            time.sleep(0.1)
            mids.put(mid)
def run_s(Uids,client):
    global Navy_followers
    while True:
        time.sleep(0.1)
        if Uids.empty():
            print "队列中已无对象"
            return Navy_followers
        mid = Uids.get()
        try:
            time.sleep(0.1)
            total_num = client.get.friendships__followers(uid = mid,count = 200).total_number
            i = 0
            print total_num
            while i <total_num:
                try:
                    users = client.get.friendships__followers(uid = mid,count = 200,cursor = i).users
                    i = i + 200
                    for m in users:
                        Navy_followers.add(m.idstr)
                except:
                    break
        except:
            time.sleep(0.1)
            Uids.put(mid)
def run_t(Uids,client):
    global Navi_suspects
    while True:
        if Uids.empty():
            print "队列中已无对象"
            return Navy_suspects
        Uid = Uids.get()
        try:
            temp = identify_navy(client,Uid,Navy_initial)#判断是否为水军
            if temp == 0:
                Navy_suspects.add(Uid)
                print Uid
            else:
                pass
        except:
            time.sleep(0.1)
            pass
            #Uids.put(Uid)
try:
    start = time.clock()

    #step 1 定义 app key，app secret， user name, user password：

    APP_KEY = "1262673699"
    APP_SECRET = "6185cf040b403dfa35de9678b5e35baf"

    USER_NAME = "18610491651"  #授权用户名
    USER_PASSWD = "zsdc12"  #授权用户密码

    #step 2 获取OAuth2.0 Access Token:
    client = APIClient(app_key=APP_KEY, app_secret=APP_SECRET)
    r = client.request_access_token(0, None, USER_NAME, USER_PASSWD)
    client.set_access_token(r.access_token, r.expires_in)

    #step 3 使用获得的OAuth2.0 Access Token调用API
    # print client.get.account__get_uid()
    print r
    print "本时段剩余访问次数：", client.get.account__rate_limit_status().remaining_ip_hits
    """
    search_query = "马航飞机失联"
    start_time = time.mktime(time.strptime("2014-3-11 00:00:00",'%Y-%m-%d %H:%M:%S'))
    end_time = time.mktime(time.strptime("2010-1-1 00:00:00",'%Y-%m-%d %H:%M:%S'))
    mid_list = get_statuses_ids_by_query(client,search_query,start_time,end_time)
    """
    #mid_list = get_statuses_ids_by_uid(client,1197161814)
    mid_list = [3694594404925087,3694602248392805,3694600436932257,3694597027309065,3694598775524305,3694592102387848,3694592900178396,3694596956438658,3694601669488289,3694596825328412]
    print '微博ID列表获取完毕'
    info = {}#对搜索内容微博的转发信息字典key = 微博id value = 转发名单列表
    queue=Queue()
    thlist = []
    all_id_table = {}
    Navy_initial=set()
    Normal_initial = set()
    for x in mid_list:
        queue.put(x)
    for i in range(0,9):
        thlist.append(threading.Thread(target=run,args=(queue,client)))
    for x in thlist:
        x.start()
    for x in thlist:
        x.join()
    for x in all_id_table.keys():
        if all_id_table.get(x) > 5:
            Navy_initial.add(x)
        else:
            pass
    print "初始化水军库准备完毕！"
    """
    queue_s=Queue()
    thlist_s = []
    Navy_followers = set()
    for m in Navy_initial:
        queue_s.put(m)
    for i in range(0,29):
        thlist_s.append(threading.Thread(target=run_s,args=(queue_s,client)))
    for x in thlist_s:
        x.start()
    for x in thlist_s:
        x.join()
    #Navy_followers = get_navy_followers(client,Navy_initial)#获取水军的粉丝
    print '水军粉丝获取完毕!'
    #print identify_navy(client,3228905747,Navy_initial)
    Navy_suspects = set()#定义备选水军库
    thlist_t = []
    queue_t=Queue()
    for x in Navy_followers:
        queue_t.put(x)
    for i in range(0,199):
        thlist_t.append(threading.Thread(target=run_t,args=(queue_t,client)))
    for x in thlist_t:
        x.start()
    for x in thlist_t:
        x.join()
    print '水军库增加完毕'
    """
    f = open('Navy003.txt','a')
    #for x in Navy_suspects:
        #f.write(x)
    for x in Navy_initial:
        f.write(x)
        f.write('\n')
    f.close()
    f = open('Normal003.txt','a')
    for x in Normal_initial:
        f.write(x)
        f.write('\n')
    f.close()
except Exception as pyOauth2Error:
        print pyOauth2Error    
